package com.amap.demo;

import com.alibaba.fastjson2.JSONObject;
import java.util.HashMap;
import java.util.Map;

/**
 * 自动测试类：验证签名生成与验签逻辑
 */
public class SignTest {

    // 测试用核心参数（模拟高德接口请求参数）
    private static Map<String, String> buildTestParams() {
        Map<String, String> params = new HashMap<>();
        // 基础公共参数
        params.put("app_id", "202210130194031937"); // 示例app_id
        params.put("utc_timestamp", "1666936656706"); // 示例时间戳
        params.put("version", "1.0"); // 接口版本
        params.put("charset", "UTF-8"); // 编码格式
        params.put("sign_type", "RSA2"); // 签名类型（与算法一致）
        params.put("method", "amap.brand.createShop.audit.callback"); // 示例接口方法
        // 业务参数（JSON格式）
        JSONObject bizContent = new JSONObject();
        bizContent.put("merchantId", "8888777711119999");
        bizContent.put("shopId", "123");
        bizContent.put("shopStatus", 1);
        params.put("biz_content", bizContent.toString());
        return params;
    }

    /**
     * 场景1：正常流程（生成签名→验签成功）
     * 预期结果：验签返回true
     */
    private static void testSignAndVerify_Success() throws Exception {
        System.out.println("======================================");
        System.out.println("【场景1】正常流程（生成签名→验签成功）");
        System.out.println("预期结果：验签返回 true");
        // 1. 构造测试参数
        Map<String, String> params = buildTestParams();

        // 2. 用商家私钥生成签名（GenerateSignUtils）
        String sign = GenerateSignUtils.generateSign(params);
        System.out.println("生成的签名：" + sign);

        // 3. 将签名放入参数，用高德公钥验签（CheckSignUtils）
        params.put("sign", sign);
        boolean verifyResult = CheckSignUtils.checkSign(params);
        System.out.println("实际验签结果：" + verifyResult);
        System.out.println("【场景1】测试结束：" + (verifyResult ? "通过" : "失败"));
        System.out.println("======================================\n");
    }

    /**
     * 场景2：参数篡改（修改参数值后验签）
     * 预期结果：验签返回false（签名基于原参数，篡改后内容不匹配）
     */
    private static void testSignAndVerify_Fail_ParamModified() throws Exception {
        System.out.println("======================================");
        System.out.println("【场景2】参数篡改（修改时间戳后验签）");
        System.out.println("预期结果：验签返回 false");
        // 1. 构造参数并生成签名
        Map<String, String> params = buildTestParams();
        String sign = GenerateSignUtils.generateSign(params);
        params.put("sign", sign);
        // 2. 篡改参数值（修改时间戳：原1666936656706 → 新1666936656707）
        params.put("utc_timestamp", "1666936656707");
        System.out.println("篡改后参数：utc_timestamp = " + params.get("utc_timestamp"));

        // 3. 验签
        boolean verifyResult = CheckSignUtils.checkSign(params);
        System.out.println("实际验签结果：" + verifyResult);
        System.out.println("【场景2】测试结束：" + (!verifyResult ? "通过" : "失败"));
        System.out.println("======================================\n");
    }

    /**
     * 场景3：错误签名（手动设置无效签名）
     * 预期结果：验签返回false
     */
    private static void testSignAndVerify_Fail_InvalidSign() throws Exception {
        System.out.println("======================================");
        System.out.println("【场景3】错误签名（手动设置无效值）");
        System.out.println("预期结果：验签返回 false");
        // 1. 构造参数（手动设置错误签名）
        Map<String, String> params = buildTestParams();
        String invalidSign = "invalid_sign_123456_abcdef";
        params.put("sign", invalidSign);
        System.out.println("使用的错误签名：" + invalidSign);

        // 2. 验签
        boolean verifyResult = CheckSignUtils.checkSign(params);
        System.out.println("实际验签结果：" + verifyResult);
        System.out.println("【场景3】测试结束：" + (!verifyResult ? "通过" : "失败"));
        System.out.println("======================================\n");
    }

    /**
     * 场景4：参数缺失（缺少必要业务参数后补全）
     * 预期结果：验签返回false（待签名字符串不匹配）
     */
    private static void testSignAndVerify_Fail_MissingParam() throws Exception {
        System.out.println("======================================");
        System.out.println("【场景4】参数缺失（先删biz_content，生成签名后补全）");
        System.out.println("预期结果：验签返回 false");
        // 1. 构造参数（删除核心业务参数biz_content）
        Map<String, String> params = buildTestParams();
        params.remove("biz_content");
        System.out.println("生成签名时的参数：已删除 biz_content");

        // 2. 基于缺失参数生成签名
        String sign = GenerateSignUtils.generateSign(params);
        params.put("sign", sign);
        System.out.println("基于缺失参数生成的签名：" + sign);

        // 3. 补全biz_content（此时待签名字符串与签名时不一致）
        JSONObject newBizContent = new JSONObject();
        newBizContent.put("merchantId", "8888777711119999");
        params.put("biz_content", newBizContent.toString());
        System.out.println("补全后的biz_content：" + newBizContent.toString());

        // 4. 验签
        boolean verifyResult = CheckSignUtils.checkSign(params);
        System.out.println("实际验签结果：" + verifyResult);
        System.out.println("【场景4】测试结束：" + (!verifyResult ? "通过" : "失败"));
        System.out.println("======================================\n");
    }

    /**
     * 场景5：参数为空（传入null）
     * 预期结果：抛出异常（工具类无法处理null参数）
     */
    private static void testSignAndVerify_Fail_NullParam() {
        System.out.println("======================================");
        System.out.println("【场景5】参数为空（传入null）");
        System.out.println("预期结果：调用验签/生成签名时抛出异常");

        // 测试1：验签传入null
        boolean checkSignThrow = false;
        try {
            CheckSignUtils.checkSign(null);
        } catch (Exception e) {
            checkSignThrow = true;
            System.out.println("验签传入null：成功抛出异常，信息：" + e.getMessage().substring(0, 50) + "...");
        }

        // 测试2：生成签名传入null
        boolean generateSignThrow = false;
        try {
            GenerateSignUtils.generateSign(null);
        } catch (Exception e) {
            generateSignThrow = true;
            System.out.println("生成签名传入null：成功抛出异常，信息：" + e.getMessage().substring(0, 50) + "...");
        }

        // 判断是否符合预期
        boolean testPass = checkSignThrow && generateSignThrow;
        System.out.println("【场景5】测试结束：" + (testPass ? "通过" : "失败"));
        System.out.println("======================================\n");
    }

    // ------------------- main方法：执行所有测试 -------------------
    public static void main(String[] args) {
        System.out.println("========== 开始执行所有签名验证测试场景 ==========\n");
        try {
            // 依次执行5个测试场景
            testSignAndVerify_Success();
            testSignAndVerify_Fail_ParamModified();
            testSignAndVerify_Fail_InvalidSign();
            testSignAndVerify_Fail_MissingParam();
            testSignAndVerify_Fail_NullParam();

            System.out.println("========== 所有测试场景执行完毕 ==========");
        } catch (Exception e) {
            // 捕获未预料的异常，避免测试中断（正常场景下此分支不会触发）
            System.err.println("========== 测试执行异常：" + e.getMessage() + " ==========");
            e.printStackTrace();
        }
    }
}